﻿/**
//  Processor.cs
//  Marquee Moment
//  Copyright 2011 Systematix Technocrates. All rights reserved.
**/
using System.Collections;
using System.Threading;

namespace MarqueeMoment.CameraController
{
    public class Processor
    {
        protected Thread thread;

        //// Flag for this thread running or not

        protected bool running;
        //// queue  

        protected Queue queue = new Queue();
        //// End application command

        protected Command.Command closeCommand;
        //// Sync object

        protected readonly object syncObject = new object();

        public Processor()
        {
            this.running = false;
            this.closeCommand = null;
            this.thread = new Thread(run);
        }


        //protected override void Finalize()
        ~Processor()
        {
            clear();
        }



        //// Set end application command
        public void setCloseCommand(Command.Command closeCommand)
        {
            this.closeCommand = closeCommand;
        }



        public void enqueue(Command.Command command)
        {
            if ((command == null) == true)
            {
                System.Environment.Exit(0);
            }

            try
            {
                Monitor.Enter(syncObject);

                this.queue.Enqueue(command);

                Monitor.PulseAll(syncObject);

            }
            finally
            {
                Monitor.Exit(syncObject);
            }

        }




        public void stopTh()
        {
            try
            {
                Monitor.Enter(syncObject);

                this.running = false;

                Monitor.PulseAll(syncObject);


            }
            finally
            {
                Monitor.Exit(syncObject);

            }

        }


        public void @join()
        {
            thread.Join();
            thread = null;

        }



        public void clear()
        {
            Monitor.Enter(syncObject);


            try
            {
                this.queue.Clear();


            }
            finally
            {
                Monitor.Exit(syncObject);

            }
        }



        public void start()
        {
            this.thread.Start();

        }




        public void run()
        {
            this.running = true;


            while (this.running)
            {
                System.Threading.Thread.Sleep(1);

                Command.Command command = take();


                if ((command == null) == false)
                {
                    bool complete = command.execute();

                    if (complete == false)
                    {
                        // >Retry 
                        // When a command execution failed with DeviceBusy or some errors,
                        // and you want to set some retrying sequence, you should sleep _
                        // about 500 micro seconds because it makes camera unstable.
                        Thread.Sleep(500);

                        enqueue(command);
                    }
                    else
                    {
                        command = null;
                    }

                }

            }

            //// Clear the queue.
            clear();

            //// End application
            if ((closeCommand == null) == false)
            {
                this.closeCommand.execute();
                this.closeCommand = null;
            }

        }


        ////take a command from the queue
        protected Command.Command take()
        {

            Command.Command command = null;


            try
            {
                Monitor.Enter(syncObject);

                //// Wait when the queue is empty.
                while (queue.Count == 0 & running == true)
                {
                    Monitor.Wait(syncObject);
                }


                if (running == true)
                {
                    command = (Command.Command)queue.Dequeue();
                }

                Monitor.PulseAll(syncObject);

            }
            finally
            {
                Monitor.Exit(syncObject);
            }


            return command;

        }


    }
}
